#include "Model.hpp"
using namespace Assimp;
using namespace glm;

Model::Model(std::string mdlPath)
{
	init(mdlPath);
}
void Model::init(std::string mdlPath)
{
	meshes = {};
	texture_cache = {};
	path = mdlPath.substr(0, mdlPath.find_last_of('/'));

	Importer importer;
	const aiScene* scene = importer.ReadFile(mdlPath, aiProcess_Triangulate | aiProcess_OptimizeGraph
							| aiProcess_OptimizeMeshes | aiProcess_JoinIdenticalVertices);

	std::cout << importer.GetErrorString();
	getMeshes(scene->mRootNode, scene);
}
void Model::draw() const
{
	for (const Mesh& mesh : meshes)
	{
		mesh.draw();
	}
};
//Model::~Model()
//{
//	for (Mesh& mesh : meshes)
//	{
//		mesh.vbo.Delete();
//		mesh.ibo.Delete();
//		glDeleteVertexArrays(1, &mesh.vao);
//	}
//}
void Model::getMeshes(aiNode* node, const aiScene* scene)
{
	meshes.reserve(node->mNumMeshes);
	for (uint32_t i = 0; i < node->mNumMeshes; i++)
	{
		aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
		meshes.push_back(createMesh(mesh, scene));
	}

	for (uint64_t i = 0; i < node->mNumChildren; i++)
	{
		getMeshes(node->mChildren[i], scene);
	}
}
Mesh Model::createMesh(aiMesh* mesh, const aiScene* scene)
{
	std::vector<Vertex> vertices;
	std::vector<uint32_t> indices;
	vertices.reserve(mesh->mNumVertices);
	size_t num_indices = 0;

	for (uint32_t i = 0; i < mesh->mNumVertices; i++)
	{
		Vertex vertex = {};
		vertex.Coord = vec3
		(
			mesh->mVertices[i].x,
			mesh->mVertices[i].y,
			mesh->mVertices[i].z
		);
		vertex.Normal = vec3
		(
			mesh->mNormals[i].x,
			mesh->mNormals[i].y,
			mesh->mNormals[i].z
		);
		vertex.TexCoord = vec2
		(
			mesh->mTextureCoords[0][i].x,
			mesh->mTextureCoords[0][i].y
		);
		vertices.push_back(vertex);
	}


	for (uint64_t i = 0; i < mesh->mNumFaces; i++)
	{
		num_indices += mesh->mFaces[i].mNumIndices;
	}

	indices.reserve(num_indices);

	for (uint64_t i = 0; i < mesh->mNumFaces; i++)
	{
		for (uint64_t j = 0; j < mesh->mFaces[i].mNumIndices; j++)
		{
			indices.push_back(mesh->mFaces[i].mIndices[j]);
		}
	}


	aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
	loadTextures(material, aiTextureType_DIFFUSE, "diffuse");
	loadTextures(material, aiTextureType_SPECULAR, "specular");
	//loadTextures(material, aiTextureType_NORMALS, "normals");

	return Mesh(vertices, indices);
}
void Model::loadTextures(const aiMaterial* material, const aiTextureType aitype, std::string type)
{
	for (uint64_t i = 0; i < material->GetTextureCount(aitype); i++)
	{
		aiString filename;
		material->GetTexture(aitype, i, &filename);

		bool skip = false;
		for (Texture* texture : texture_cache)
		{
			if (std::string(filename.C_Str()) == texture->name)
			{
				skip = true;
				break;
			}
		}

		if (!skip)
		{
			glActiveTexture(GL_TEXTURE0 + static_cast<int>(texture_cache.size()));
			Texture* texture = new Texture(path + "/" + std::string(filename.C_Str()), std::string(filename.C_Str()), type);
			texture_cache.push_back(texture);
		}
	}
}
